在 Kubernetes 中,Ingress
是一種 API 資源,它用來管理外部 HTTP 和 HTTPS 流量如何進入集群內部的服務。Ingress 通常使用域名和路由規則將外部請求引導到集群內的特定服務,從而實現對服務的公開訪問。
下面是 Ingress 的一個簡單示例,可將所有流量都傳送到同一 Service:
Ingress
提供了一個集中管理 HTTP 和 HTTPS 路由的方式,它能夠根據請求的主機名、路徑、Header 等信息,將請求路由到適當的 Kubernetes 服務。這與傳統的 Service
相比,提供了更靈活和細緻的流量控制。使用 Ingress 可以避免每個服務都需要創建一個 LoadBalancer
,從而減少了對外部 IP 地址的需求,也降低了運營成本。
流量控制:Service
的 LoadBalancer
通常會為每個服務創建一個外部負載均衡器,並將所有進來的流量直接轉發到服務的後端 Pod。而 Ingress
則可以根據更複雜的路由規則(如 URL 路徑、主機名)來分發流量。
成本和資源使用:LoadBalancer
Service 每個服務都需要一個外部負載均衡器,這在雲環境中通常意味著較高的成本。相比之下,Ingress
通常只需要一個負載均衡器來處理多個服務的流量。
功能擴展:Ingress
支持多種功能,如 SSL/TLS 終止、基於名稱的虛擬主機、重寫和重定向 URL 等。這些功能通常無法通過 LoadBalancer
直接實現。
我們必須擁有一個 Ingress 控製器 才能滿足 Ingress 的要求。僅建立 Ingress 資源本身沒有任何效果。Kubernetes 本身並沒有實作 Ingress 控製器,我們可以從許多 Ingress 控製器中進行選擇並部署,例如 ingress-nginx
。本次我們使用 ingress-nginx
作為我們的 Ingress 控製器。
為了給 ingress 部署外部 IP,請確認叢集安裝了 MetalLB。安裝方式請參考之前的 Service 章節。
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.1/deploy/static/provider/cloud/deploy.yaml
kubectl get all -n ingress-nginx
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-admission-create-85zzj 0/1 Completed 0 2m12s
pod/ingress-nginx-admission-patch-8kmgv 0/1 Completed 0 2m12s
pod/ingress-nginx-controller-666487-phxw4 1/1 Running 0 2m12s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
AGE
service/ingress-nginx-controller LoadBalancer 10.96.18.93 172.20.175.140 80:30655/TCP,443:30748/TCP 2m12s
service/ingress-nginx-controller-admission ClusterIP 10.96.219.16 <none> 443/TCP
2m12s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ingress-nginx-controller 1/1 1 1 2m12s
NAME DESIRED CURRENT READY AGE
replicaset.apps/ingress-nginx-controller-666487 1 1 1 2m12s
NAME STATUS COMPLETIONS DURATION AGE
job.batch/ingress-nginx-admission-create Complete 1/1 10s 2m12s
job.batch/ingress-nginx-admission-patch Complete 1/1 11s 2m12s
我們首先建立兩個 nginx Deployment 應用 foo
, bar
,以及對應的 service 資源。
組態檔案: ingress-test-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-foo
spec:
replicas: 1
selector:
matchLabels:
app: nginx-foo
template:
metadata:
labels:
app: nginx-foo
spec:
initContainers:
- name: modify-index-html
image: busybox
command: ["/bin/sh", "-c"]
args:
- echo "foo" > /usr/share/nginx/html/index.html
volumeMounts:
- name: web-content-foo
mountPath: /usr/share/nginx/html
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: web-content-foo
mountPath: /usr/share/nginx/html
volumes:
- name: web-content-foo
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: nginx-foo-service
spec:
selector:
app: nginx-foo
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-bar
spec:
replicas: 1
selector:
matchLabels:
app: nginx-bar
template:
metadata:
labels:
app: nginx-bar
spec:
initContainers:
- name: modify-index-html
image: busybox
command: ["/bin/sh", "-c"]
args:
- echo "bar" > /usr/share/nginx/html/index.html
volumeMounts:
- name: web-content-bar
mountPath: /usr/share/nginx/html
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: web-content-bar
mountPath: /usr/share/nginx/html
volumes:
- name: web-content-bar
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: nginx-bar-service
spec:
selector:
app: nginx-bar
ports:
- protocol: TCP
port: 80
targetPort: 80
kubectl apply -f ingress-test-app.yaml
接下來,我們會實現以下情境並測試。
這是最基本的路由情境,僅暴露單一的 Service。
組態檔案: ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: basic-ingress
spec:
ingressClassName: nginx
defaultBackend:
service:
name: nginx-foo-service
port:
number: 80
kubectl apply -f ingress.yaml
kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
basic-ingress nginx * 172.20.175.140 80 26m
$ docker exec -it wslkind-control-plane /bin/sh
# curl 172.20.175.140
foo
kubectl delete -f ingress.yaml
這個路由方法是以路徑為條件,將流量導向不同的 Service。
示意圖如下:
組態檔案: ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-ingress
annotations:
# URL 重定向。
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /foo
pathType: Prefix
backend:
service:
name: nginx-foo-service
port:
number: 80
- path: /bar
pathType: Prefix
backend:
service:
name: nginx-bar-service
port:
number: 80
kubectl apply -f ingress.yaml
一樣等待一段時間,直到 ingress 分配地址。
$ docker exec -it wslkind-control-plane /bin/sh
# curl 172.20.175.140:80/foo
foo
# curl 172.20.175.140:80/bar
bar
kubectl delete -f ingress.yaml
這個路由方法是以 Hostname 為條件,將流量導向不同的 Service。
示意圖如下:
由於 host 是我們自定義的,需要修改訪問環境的 hosts 表。我們是在 control-plane 節點測試,需要在這個節點內修改 hosts。
docker exec -it wslkind-control-plane /bin/sh
# apt-get update
# apt-get install vim
vim /etc/hosts
編輯 hosts 列表127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.3 wslkind-control-plane
fc00:f853:ccd:e793::3 wslkind-control-plane
從 Basic Ingress 的實作中我們已經得知,ingress 的 IP 是 172.20.175.140
。
最下面加入 172.20.175.140 foo.example.com
保存退出
測試 foo.example.com
curl foo.example.com
---
foo
重新修改 /etc/hosts
,將剛剛加入的內容修改為 172.20.175.140 bar.example.com
保存退出
測試 bar.example.com
# curl bar.example.com
---
bar
Ingress 提供了強大的 HTTP/HTTPS 流量管理能力,適合那些需要集中管理多個服務入口、SSL/TLS 加密或複雜路由規則的應用場景。
Ingress 和 Ingress Controller 的功能與 AWS 上的 ELB (Elastic Load Balancer) 類似。對於熟悉 AWS 的朋友,可以藉由理解 AWS ELB 開始入手來學習 Ingress 的概念。